#!/usr/bin/env python
# -*- coding: UTF-8 -*-

import os
import shutil
import sys

execfile(os.path.join(sys.path[0], "framework.py"))

from oriolusdocker.docker import DockerFactory, DockerError
from oriolusdocker.storages.memorystorage import MemoryStorage
from oriolusgaffer.cache import Cache
from oriolusgaffer.gaffer.selectstrategy import LatestStrategy
from oriolusgaffer.gaffer.catalogue import Catalogue
from oriolusgaffer.gaffer import Gaffer, GafferError
from orioluspith.packets.meta import Meta
from orioluspith.packets.packet import Packet, Status
from pmock import *
from unittest import TestCase, TestLoader, TextTestRunner

class TestRemove(TestCase):
    def setUp(self):
        self.__test_packets_path = os.path.join(".", "testdata", "testpackets")

        self.__cache_path = os.path.join(".", "testdata", "gaffer_cache")
        self.__temp_dirs = (self.__cache_path, )

        self.__setup_mocks()

    def tearDown(self):
        for path in self.__temp_dirs:
            if os.path.exists(path):
                shutil.rmtree(path)
                
    def test_remove01(self):
        self.__memory_storage.add(Packet(Meta("packet_a", "1.2.3.4", None, [], [], [])))
        self.__memory_storage.add(Packet(Meta("packet_b", "2.3.4.5", None, [], [], [{"Name": "packet_a", "Version": "1.2.3.4"}])))

        packets_to_remove = ("packet_a-1.2.3.4", )
        
        self.assertRaises(GafferError, self.__gaffer.remove, packets_to_remove)
        self.__mock_docker.verify()

    def test_remove02(self):
        self.__memory_storage.add(Packet(Meta("packet_a", "1.2.3.4", None, [], [], [])))
        self.__memory_storage.add(Packet(Meta("packet_b", "2.3.4.5", None, [], [], [])))
        self.__memory_storage.add(Packet(Meta("packet_c", "3.4.5.6", None, [], [], [])))

        packets_to_remove = ("packet_a-1.2.3.4", "packet_b-2.3.4.5", "packet_c-3.4.5.6")
        
        expected_docker_actions = ("remove(eq('packet_a-1.2.3.4'))",
                                   "remove(eq('packet_b-2.3.4.5'))",
                                   "remove(eq('packet_c-3.4.5.6'))", )

        self.assert_remove(packets_to_remove, expected_docker_actions)
        
    def test_remove03(self):
        self.__memory_storage.add(Packet(Meta("packet_a", "1.2.3.4", None, [], [], [])))
        self.__memory_storage.add(Packet(Meta("packet_b", "2.3.4.5", None, [], [], [{"Name": "packet_a", "Version": "1.2.3.4"}])))
        self.__memory_storage.add(Packet(Meta("packet_c", "3.4.5.6", None, [], [], [{"Name": "packet_b", "Version": "2.3.4.5"}])))
        self.__memory_storage.add(Packet(Meta("packet_d", "4.5.6.7", None, [], [], [{"Name": "packet_b", "Version": "2.3.4.5"}])))
        self.__memory_storage.add(Packet(Meta("packet_e", "5.6.7.8", None, [], [], [{"Name": "packet_b", "Version": "2.3.4.5"}, {"Name": "packet_d", "Version": "4.5.6.7"}])))

        packets_to_remove = ("packet_a-1.2.3.4", "packet_b-2.3.4.5", "packet_c-3.4.5.6", "packet_d-4.5.6.7", "packet_e-5.6.7.8")
        
        expected_docker_actions = ("remove(eq('packet_c-3.4.5.6'))",
                                   "remove(eq('packet_e-5.6.7.8'))", 
                                   "remove(eq('packet_d-4.5.6.7'))", 
                                   "remove(eq('packet_b-2.3.4.5'))",
                                   "remove(eq('packet_a-1.2.3.4'))", )

        self.assert_remove(packets_to_remove, expected_docker_actions)

    def test_remove04(self):
        self.__memory_storage.add(Packet(Meta("packet_a", "1.2.3.4", None, [], [], [])))
        self.__memory_storage.add(Packet(Meta("packet_b", "2.3.4.5", None, [], [], [{"Name": "packet_a", "Version": "1.2.3.4"}])))
        self.__memory_storage.add(Packet(Meta("packet_c", "3.4.5.6", None, [], [], [{"Name": "packet_b", "Version": "2.3.4.5"}])))
        self.__memory_storage.add(Packet(Meta("packet_d", "4.5.6.7", None, [], [], [{"Name": "packet_b", "Version": "2.3.4.5"}])))
        self.__memory_storage.add(Packet(Meta("packet_e", "5.6.7.8", None, [], [], [{"Name": "packet_b", "Version": "2.3.4.5"}, {"Name": "packet_d", "Version": "4.5.6.7"}])))

        packets_to_remove = ("packet_a-1.2.3.4", "packet_b-2.3.4.5", "packet_d-4.5.6.7", "packet_e-5.6.7.8")

        self.assertRaises(GafferError, self.__gaffer.remove, packets_to_remove)
        self.__mock_docker.verify()

    def test_remove05(self):
        self.__memory_storage.add(Packet(Meta("packet_a", "1.2.3.4", None, [], [], [])))
        self.__memory_storage.add(Packet(Meta("packet_b", "2.3.4.5", None, [], [], [{"Name": "packet_a", "Version": "1.2.3.4"}])))
        self.__memory_storage.add(Packet(Meta("packet_c", "3.4.5.6", None, [], [], [])))

        packets_to_remove = ("packet_a-1.2.3.4", "packet_b-2.3.4.5", "packet_c-3.4.5.6")

        expected_docker_actions = ("remove(eq('packet_b-2.3.4.5'))",
                                   "remove(eq('packet_c-3.4.5.6'))",
                                   "remove(eq('packet_a-1.2.3.4'))", )

        self.assert_remove(packets_to_remove, expected_docker_actions)

    def test_remove06(self):
        self.__memory_storage.add(Packet(Meta("packet_a", "1.2.3.1", None, [], [], [])))
        self.__memory_storage.add(Packet(Meta("packet_a", "1.2.3.2", None, [], [], [])))
        self.__memory_storage.add(Packet(Meta("packet_b", "2.3.4.5", None, [], [], [{"Name": "packet_a", "Version": "[1.2.3.1, 1.2.3.2]"}])))

        packets_to_remove = ("packet_a-1.2.3.1", )

        expected_docker_actions = ("remove(eq('packet_a-1.2.3.1'))", )

        self.assert_remove(packets_to_remove, expected_docker_actions)

    def test_remove07(self):
        self.__memory_storage.add(Packet(Meta("packet_a", "1.2.3.1", None, [], [], [])))
        self.__memory_storage.add(Packet(Meta("packet_a", "1.2.3.2", None, [], [], [])))
        self.__memory_storage.add(Packet(Meta("packet_b", "2.3.4.5", None, [], [], [{"Name": "packet_a", "Version": "[1.2.3.1, 1.2.3.2]"}])))

        packets_to_remove = ("packet_a-1.2.3.1", "packet_a-1.2.3.2",)

        expected_docker_actions = ("remove(eq('packet_a-1.2.3.1'))", )

        self.assertRaises(GafferError, self.__gaffer.remove, packets_to_remove)
        self.__mock_docker.verify()

    def test_remove08(self):
        self.__memory_storage.add(Packet(Meta("packet_a", "1.2.3.1", None, [], [], [])))
        self.__memory_storage.add(Packet(Meta("packet_a", "1.2.3.2", None, [], [], [])))
        self.__memory_storage.add(Packet(Meta("packet_b", "2.3.4.5", None, [], [], [{"Name": "packet_a", "Version": "[1.2.3.1, 1.2.3.2]"}])))

        packets_to_remove = ("packet_a-1.2.3.1", "packet_b-2.3.4.5", "packet_a-1.2.3.2", )

        expected_docker_actions = ("remove(eq('packet_a-1.2.3.1'))",
                                   "remove(eq('packet_b-2.3.4.5'))",
                                   "remove(eq('packet_a-1.2.3.2'))", )

        self.assert_remove(packets_to_remove, expected_docker_actions)

    def test_remove09(self):
        self.__memory_storage.add(Packet(Meta("packet_a", "1.2.3.1", None, [], [], [])))
        self.__memory_storage.add(Packet(Meta("packet_a", "1.2.3.2", None, [], [], [])))
        self.__memory_storage.add(Packet(Meta("packet_b", "2.3.4.5", None, [], [], [{"Name": "packet_a", "Version": "[1.2.3.1, 1.2.3.2]"}])))

        packets_to_remove = ("packet_a-1.2.3.1", "packet_a-1.2.3.2", "packet_b-2.3.4.5", )

        expected_docker_actions = ("remove(eq('packet_a-1.2.3.1'))",
                                   "remove(eq('packet_b-2.3.4.5'))",
                                   "remove(eq('packet_a-1.2.3.2'))", )

        self.assert_remove(packets_to_remove, expected_docker_actions)

    def test_remove10(self):
        self.__memory_storage.add(Packet(Meta("packet_a", "1.2.3.1", None, [], [], [])))
        self.__memory_storage.add(Packet(Meta("packet_a", "1.2.3.2", None, [], [], [])))
        self.__memory_storage.add(Packet(Meta("packet_b", "2.3.4.5", None, [], [], [{"Name": "packet_a", "Version": "1.2.3.2"}])))
        self.__memory_storage.add(Packet(Meta("packet_c", "3.4.5.6", None, [], [], [{"Name": "packet_a", "Version": "[1.2.3.1, 1.2.3.2]"}])))

        packets_to_remove = ("packet_a-1.2.3.1", )

        expected_docker_actions = ("remove(eq('packet_a-1.2.3.1'))", )

        self.assert_remove(packets_to_remove, expected_docker_actions)

    def test_remove11(self):
        self.__memory_storage.add(Packet(Meta("packet_a", "1.2.3.1", None, [], [], [])))
        self.__memory_storage.add(Packet(Meta("packet_a", "1.2.3.2", None, [], [], [])))
        self.__memory_storage.add(Packet(Meta("packet_b", "2.3.4.5", None, [], [], [{"Name": "packet_a", "Version": "1.2.3.2"}])))
        self.__memory_storage.add(Packet(Meta("packet_c", "3.4.5.6", None, [], [], [{"Name": "packet_a", "Version": "[1.2.3.1, 1.2.3.2]"}])))

        packets_to_remove = ("packet_a-1.2.3.1", "packet_a-1.2.3.2", "packet_c-3.4.5.6", "packet_b-2.3.4.5",)

        expected_docker_actions = ("remove(eq('packet_a-1.2.3.1'))",
                                   "remove(eq('packet_c-3.4.5.6'))",
                                   "remove(eq('packet_b-2.3.4.5'))",
                                   "remove(eq('packet_a-1.2.3.2'))", )

        self.assert_remove(packets_to_remove, expected_docker_actions)
                
    def __setup_mocks(self):
        cache = Cache(self.__cache_path)
        self.__mock_docker = Mock()
        self.__mock_trotter = Mock()
        catalogue = Catalogue(self.__mock_trotter)
        
        select_strategy = LatestStrategy()
        self.__gaffer = Gaffer(cache, self.__mock_docker, self.__mock_trotter, catalogue, select_strategy)
        
        self.__memory_storage = MemoryStorage()
        self.__mock_docker.stubs().extract_storage().will(return_value(self.__memory_storage))

        self.__mock_virtual_docker = None
        self.__original_mock_virtual_docker_install = None
        self.__exceptional_packet_path = None

    def assert_remove(self, packets_to_remove, expected_docker_actions):
        mock_docker = self.__mock_docker

        for i in range(len(expected_docker_actions)):
            action = expected_docker_actions[i]

            if i == 0:
                eval("mock_docker.expects(once()).%s.id(i)" % action)
            else:
                eval("mock_docker.expects(once()).%s.id(i).after(i-1)" % action)

        self.__gaffer.remove(packets_to_remove)
        self.__mock_docker.verify()


if __name__ == "__main__":
    suite = TestLoader().loadTestsFromTestCase(TestRemove)
    TextTestRunner(verbosity=2).run(suite)